package com.jonlandrum.selfbalancingtree;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class NodeTest {
    private Node<String> root;
    
    @Before
    public void init() {
        root = new Node<String>();
    }
    
    @After
    public void destroy() {
        root = null;
    }
    
    @Test
    public void testConstructorNull() {
        assertThat(root, instanceOf(Node.class));
    }
    
    @Test
    public void testConstructorString() {
        root = new Node<String>("Root");
        assertThat(root, instanceOf(Node.class));
    }
    
    @Test
    public void testConstructorNode() {
        root = new Node<String>(new Node<String>("Root"));
        assertThat(root, instanceOf(Node.class));
    }
    
    @Test
    public void testSetDataString() {
        assertTrue(root.isEmpty());
        root.setData("Root");
        assertFalse(root.isEmpty());
        assertEquals("Root", root.getData());
    }
    
    @Test
    public void testSetDataNode() {
        assertTrue(root.isEmpty());
        root.setData(new Node<String>("Root"));
        assertFalse(root.isEmpty());
        assertEquals("Root", root.getData());
    }
    
    @Test
    public void testSetLeftHeight() {
        assertEquals(0, root.getLeftHeight());
        root.setLeftHeight(1);
        assertEquals(1, root.getLeftHeight());
    }
    
    @Test
    public void testSetRightHeight() {
        assertEquals(0, root.getRightHeight());
        root.setRightHeight(1);
        assertEquals(1, root.getRightHeight());
    }
    
    @Test
    public void testSetParent() {
        Node<String> child = new Node<String>("Child");
        assertFalse(child.hasParent());
        child.setParent(root);
        assertTrue(child.hasParent());
    }
    
    @Test
    public void testSetLeftChild() {
        assertFalse(root.hasLeftChild());
        root.setLeftChild(new Node<String>("Child"));
        assertTrue(root.hasLeftChild());
    }
    
    @Test
    public void testSetRightChild() {
        assertFalse(root.hasRightChild());
        root.setRightChild(new Node<String>("Child"));
        assertTrue(root.hasRightChild());
    }
    
    @Test
    public void testGetDataNull() {
        assertEquals(null, root.getData());
    }
    
    @Test
    public void testGetDataString() {
        root.setData("Root");
        assertEquals("Root", root.getData());
    }
    
    @Test
    public void testGetLeftHeight() {
        assertEquals(0, root.getLeftHeight());
        root.setLeftHeight(1);
        assertEquals(1, root.getLeftHeight());
    }
    
    @Test
    public void testGetRightHeight() {
        assertEquals(0, root.getRightHeight());
        root.setRightHeight(1);
        assertEquals(1, root.getRightHeight());
    }
    
    @Test
    public void testGetHeight() {
        assertEquals(0, root.getHeight());
        root.setLeftHeight(1);
        assertEquals(1, root.getHeight());
        root.setRightHeight(2);
        assertEquals(2, root.getHeight());
    }
    
    @Test
    public void testGetBalance() {
        assertEquals(0, root.getBalance());
        root.setLeftHeight(1);
        assertEquals(-1, root.getBalance());
        root.setRightHeight(1);
        assertEquals(0, root.getBalance());
        root.setRightHeight(2);
        assertEquals(1, root.getBalance());
    }
    
    @Test
    public void testGetColorAndSwapColor() {
        assertEquals(1, root.getColor());
        root.swapColor();
        assertEquals(0, root.getColor());
        root.swapColor();
        assertEquals(1, root.getColor());
    }
    
    @Test
    public void testGetParent() {
        root.setData("Root");
        Node<String> child = new Node<String>("Child");
        child.setParent(root);
        assertEquals("Root", child.getParent().getData());
    }
    
    @Test
    public void testGetSibling() {
        root.setData("Root");
        Node<String> child = new Node<String>("Child");
        child.setParent(root);
        Node<String> gc1 = new Node<String>("Grandchild 1");
        child.setLeftChild(gc1);
        gc1.setParent(child);
        Node<String> gc2 = new Node<String>("Grandchild 2");
        child.setRightChild(gc2);
        gc2.setParent(child);
        assertEquals(null, child.getSibling().getData());
        assertEquals(gc2, gc1.getSibling());
        assertEquals(gc1, gc2.getSibling());
    }
    
    @Test
    public void testGetLeftChild() {
        root.setLeftChild(new Node<String>("Child"));
        assertEquals("Child", root.getLeftChild().getData());
    }
    
    @Test
    public void testGetRightChild() {
        root.setRightChild(new Node<String>("Child"));
        assertEquals("Child", root.getRightChild().getData());
    }
    
    @Test
    public void testGetNumChildren() {
        assertEquals(0, root.getNumChildren());
        root.setLeftChild(new Node<String>("Child1"));
        assertEquals(1, root.getNumChildren());
        root.setRightChild(new Node<String>("Child2"));
        assertEquals(2, root.getNumChildren());
        root.getLeftChild().setLeftChild(new Node<String>("Child1 of Child1"));
        assertEquals(3, root.getNumChildren());
        root.getLeftChild().setRightChild(new Node<String>("Child2 of Child1"));
        assertEquals(4, root.getNumChildren());
        root.getRightChild().setLeftChild(new Node<String>("Child1 of Child2"));
        assertEquals(5, root.getNumChildren());
        root.getRightChild().setRightChild(new Node<String>("Child2 of Child2"));
        assertEquals(6, root.getNumChildren());
        assertEquals(2, root.getLeftChild().getNumChildren());
        assertEquals(0, root.getRightChild().getRightChild().getNumChildren());
    }
    
    @Test
    public void testIsEmpty() {
        assertTrue(root.isEmpty());
        root.setData("Root");
        assertFalse(root.isEmpty());
    }
    
    @Test
    public void testIsRoot() {
        Node<String> child = new Node<String>("Child");
        root.setLeftChild(child);
        child.setParent(root);
        assertTrue(root.isRoot());
        assertFalse(child.isRoot());
    }
    
    @Test
    public void testIsLeaf() {
        assertTrue(root.isLeaf());
        root.setLeftChild(new Node<String>("Child"));
        assertFalse(root.isLeaf());
        assertTrue(root.getLeftChild().isLeaf());
    }
    
    @Test
    public void testIsLeftChild() {
        Node<String> child = new Node<String>("Child");
        assertFalse(child.isLeftChild());
        root.setLeftChild(child);
        child.setParent(root);
        assertTrue(child.isLeftChild());
    }
    
    @Test
    public void testIsRightChild() {
        Node<String> child = new Node<String>("Child");
        assertFalse(child.isRightChild());
        root.setRightChild(child);
        child.setParent(root);
        assertTrue(child.isRightChild());
    }
    
    @Test
    public void testHasParent() {
        Node<String> child = new Node<String>("Child");
        assertFalse(child.hasParent());
        child.setParent(root);
        assertTrue(child.hasParent());
    }
    
    @Test
    public void testHasSibling() {
        assertFalse(root.hasSibling());
        Node<String> child1 = new Node<String>("Child1");
        Node<String> child2 = new Node<String>("Child2");
        root.setLeftChild(child1);
        child1.setParent(root);
        root.setRightChild(child2);
        child2.setParent(root);
        assertTrue(child1.hasSibling());
        assertTrue(child2.hasSibling());
    }
    
    @Test
    public void testHasLeftChild() {
        assertFalse(root.hasLeftChild());
        root.setLeftChild(new Node<String>("Child"));
        assertTrue(root.hasLeftChild());
    }
    
    @Test
    public void testHasRightChild() {
        assertFalse(root.hasRightChild());
        root.setRightChild(new Node<String>("Child"));
        assertTrue(root.hasRightChild());
    }
    
    @Test
    public void testHasOneChild() {
        assertFalse(root.hasOneChild());
        root.setLeftChild(new Node<String>("Child"));
        assertTrue(root.hasOneChild());
        root = new Node<String>("Root");
        root.setRightChild(new Node<String>("Child"));
        assertTrue(root.hasOneChild());
        root.setLeftChild(new Node<String>("Child"));
        assertFalse(root.hasOneChild());
    }
    
    @Test
    public void testToString() {
        Node<Integer> root = new Node<Integer>();
        assertEquals("", root.toString());
        root.setData(1);
        assertEquals("1", root.toString());
    }
    
    @Test
    public void testCompareTo() {
        Node<Integer> ths = new Node<Integer>(1);
        Node<Integer> tht = new Node<Integer>(2);
        assertEquals(-1, ths.compareTo(tht));
        assertEquals(1, tht.compareTo(ths));
        tht.setData(1);
        assertEquals(0, ths.compareTo(tht));
    }
}